/*	Copyright 2007 - Xavier Baro (xbaro@cvc.uab.cat)

	This file is part of eapmlib.

    Eapmlib is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or any 
	later version.

    Eapmlib is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "ClassEnsemble.h"

// Temporal includes (must be deleted when the dynamic object creation works)
#include "ThrClassifier.h"
#include "AdditiveClassEnsemble.h"
#include "Cascade.h"

Evolutive::CClassEnsemble::CClassEnsemble(void) : CClassifier()
{	
#ifndef USE_OPENCV
	OPENCV_ERROR_CLASS("CClassEnsemble");
#endif
}

Evolutive::CClassEnsemble::~CClassEnsemble(void)
{		
	register int i;

	// Remove all the classifiers
	for(i=0;i<m_Classifiers.size();i++)
	{
		//delete m_Classifiers[i];
	}
	m_Classifiers.clear();
}

#ifdef USE_OPENCV
void Evolutive::CClassEnsemble::SetFeatureParameters(CChromosome *C)
{
	throw CEvolutiveLibException("This method is not applicable to this class.",__FILE__,__LINE__,"SetFeatureParameters");
}

void Evolutive::CClassEnsemble::GetFeatureParameters(int &NumParameters,double **Parameters)
{
	throw CEvolutiveLibException("This method is not applicable to this class.",__FILE__,__LINE__,"GetFeatureParameters");
}

Evolutive::CClassifier* Evolutive::CClassEnsemble::GetClassifier(int Idx)
{
	if(Idx<0 || Idx>=m_Classifiers.size())
	{
		throw CEvolutiveLibException("Index out of bounds",__FILE__,__LINE__,"GetClassifier");
	}

	return m_Classifiers[Idx];
}

int Evolutive::CClassEnsemble::GetNumClassifiers(void)
{
	return m_Classifiers.size();
}

void Evolutive::CClassEnsemble::AddClassifier(CClassifier *Classifier)
{
	m_ImageSize=Classifier->GetSize();
	m_Classifiers.push_back(Classifier);
}

void Evolutive::CClassEnsemble::Reset(void)
{
	m_Classifiers.clear();
}

void Evolutive::CClassEnsemble::Serialize(std::fstream &fs,bool Saving)
{
	int NumClassifiers;
	char Buffer[IO_CLASSNAME_LEN];
	register int i;
	CClassifier *pNewObject=NULL;

	// Call the base class method
	CClassifier::Serialize(fs,Saving);

	// Implement the specialized code
	if(Saving)
	{
		// Save the data to a file		
		// Store the number of classifiers
		NumClassifiers=m_Classifiers.size();
		fs.write((char*)&NumClassifiers,sizeof(int));
		// For each classifier, save the class name and serialize
		for(i=0;i<m_Classifiers.size();i++)
		{
			// Retrieve and store the class name
			strcpy(Buffer,(m_Classifiers[i]->GetClassNameID()).data());
			fs.write((char*)Buffer,IO_CLASSNAME_LEN);

			// Serialize this object
			m_Classifiers[i]->Serialize(fs,Saving);
		}
	}
	else
	{
		// Load the data from a file
		// Read the number of classifiers
		fs.read((char*)&NumClassifiers,sizeof(int));

		// Remove old classifiers
		for(i=0;i<m_Classifiers.size();i++)
		{
			delete m_Classifiers[i];
		}
		m_Classifiers.clear();

		// For each classifier, read the class name, create the correct object and serialize
		for(i=0;i<NumClassifiers;i++)
		{
			// Retrieve and store the class name			
			fs.read((char*)Buffer,IO_CLASSNAME_LEN);

			// Create a new object of this class		
			if(!strcmp(Buffer,"CThrClassifier"))
			{
				pNewObject=new CThrClassifier();						
			}
			if(!strcmp(Buffer,"CAdditiveClassEnsemble"))
			{
				pNewObject=new CAdditiveClassEnsemble();						
			}
			if(!strcmp(Buffer,"CCascade"))
			{
				pNewObject=new CCascade();						
			}			
			// TODO: Create this object without IF..THEN (LoadLibrary, dlopen, ...)

			// Serialize this object
			pNewObject->Serialize(fs,Saving);

			// Add this object to the ensemble
			AddClassifier(pNewObject);
		}
	}	
}
#endif //USE_OPENCV